<?php

namespace app\controllers;

use app\librarys\Inteface;
use app\librarys\Tools;
use app\models\Address;
use app\models\Api;
use app\models\ApiExceptionLog;
use app\models\ApiOperateLog;
use app\models\ApiResponseCode;
use app\models\Area;
use app\models\Cart;
use app\models\Goods;
use app\models\Information;
use app\models\Institution;
use app\models\Integral;
use app\models\MallFrontEnd;
use app\models\Open;
use app\models\Order;
use app\models\User;
use app\exceptions\ApiAccountMissingException;
use yii\base\ErrorException;
use yii\base\Exception;
use yii\web\Controller;

class ApiController extends Controller
{
    public $enableCsrfValidation = false;
    public $layout = false;

    private $_request = null;
    private $_openConfig = null;

    const CacheKeyPrefix = 'api.cache_key.';
    const CacheDuration = 600; // 10minute

//    /**
//     * 根据域名来获取机构信息
//     * @return string
//     */
//    public function actionGetInstitutionByDomain()
//    {
//        $domain = $this->_getRequestValue('domain');
//        $item = Institution::getInstitutionByDomain($domain);
//        return $this->renderJson($item);
//    }
//

    /**
     * 根据机构编码来获取机构信息
     * @return string
     */
    public function actionGetInstitutionByCode()
    {
        $institutionCode = $this->_getInstitutionCode();

        $cacheKey = self::CacheKeyPrefix . 'actionGetInstitutionByCode:' . $institutionCode;
        $item = \Yii::$app->cache->get($cacheKey);
        if ($item == false) {
            $item = Institution::getInstitutionByCode($institutionCode);
            \Yii::$app->cache->set($cacheKey, $item, self::CacheDuration);
        }

        return $this->renderJson($item);
    }

    /**
     * 获取商品分类列表
     * @return string
     */
    public function actionGetGoodsCategoryList()
    {
        $institutionCode = $this->_getInstitutionCode();

        $cacheKey = self::CacheKeyPrefix . 'actionGetGoodsCategoryList:' . $institutionCode;
        $items = \Yii::$app->cache->get($cacheKey);
        if ($items == false) {
            $items = Goods::getGoodsCategoryListWithHierarchy($institutionCode);
            \Yii::$app->cache->set($cacheKey, $items, self::CacheDuration);
        }

        return $this->renderJson($items);
    }

    /**
     * 获取商品列表
     * @return string
     */
    public function actionGetGoodsList()
    {
        $institutionCode = $this->_getInstitutionCode();
        $page = $this->_getRequestValue('page', 1);
        $pageSize = $this->_getRequestValue('page_size', 10);
        $goodsCode = ''; //$this->_getRequestValue('goods_code', '');
        $goodsName = $this->_getRequestValue('goods_name', '');
        $goodsCategoryCode = $this->_getRequestValue('goods_category_code', '');
        $isNewest = ''; //$this->_getRequestValue("is_newest", '');
        $isHot = ''; //$this->_getRequestValue("is_hot", '');
        $integralFrom = $this->_getRequestValue("integral_from", '');
        $integralTo = $this->_getRequestValue("integral_to", '');
        $sort = $this->_getRequestValue('sort', 0); //1:按价格从小到大; 2:按价格从大到小; 3:按上架时间从新到旧; 4:按上架时间从旧到新

        $count = Api::getGoodsListCountBySearch($institutionCode, $goodsCode, $goodsName, $goodsCategoryCode, $isNewest, $isHot, $integralFrom, $integralTo);

        $items = Api::getGoodsListBySearch($institutionCode, $page, $pageSize, $goodsCode, $goodsName, $goodsCategoryCode, $isNewest, $isHot, $integralFrom, $integralTo, $sort);

        $result = [
            'count' => $count,
            'page' => $page,
            'page_size' => $pageSize,
            'list' => $items
        ];
        return $this->renderJson($result);
    }

//    /**
//     * 获取热销商品列表
//     */
//    public function actionGetHotGoodsList()
//    {
//        $institutionCode = $this->_getInstitutionCode();
//        $item = MallFrontEnd::getHotGoodsList($institutionCode);
//        return $this->renderJson($item);
//    }

    /**
     * 获取商品详情
     * @return string
     */
    public function actionGetGoodsDetail()
    {
        $institutionCode = $this->_getInstitutionCode();
        $goodsCode = $this->_getRequestValue('goods_code');

        $cacheKey = self::CacheKeyPrefix . 'actionGetGoodsDetail:' . $institutionCode . '#' . $goodsCode;

        $item = \Yii::$app->cache->get($cacheKey);
        if ($item == false) {
            $item = Api::getGoodsDetail($institutionCode, $goodsCode);
            \Yii::$app->cache->set($cacheKey, $item, self::CacheDuration);
        }

        return $this->renderJson($item);
    }

    /**
     * 获取商品库存
     * @return string
     */
    public function actionGetGoodsStock()
    {
        $goodsCode = $this->_getRequestValue('goods_code');
        $item = Goods::getGoodsStock($goodsCode);
        return $this->renderJson($item);
    }

//    /**
//     * 发送短信验证码
//     * @return string
//     * @throws \Exception
//     */
//    public function actionSendSmsVerificationCode()
//    {
//        $institutionCode = $this->_getInstitutionCode();
//        $phone = $this->_getRequestValue('phone');
//
//        $user = User::getUserByPhone($institutionCode, $phone);
//        if ($user == null) {
//            throw new \Exception('此机构无此用户!');
//        }
//        $status = User::sendSmsVerificationCode($phone);
//
//        if ($status == true) {
//            return $this->renderJson();
//        } else {
//            return $this->renderJson(null, ApiResponseCode::ExceptionCode, ApiResponseCode::ExceptionMessage);
//        }
//    }

//    /**
//     * 使用手机号码和短信验证码进行登录
//     * @return string
//     */
//    public function actionLoginWithPhone()
//    {
//        $institutionCode = $this->_getInstitutionCode();
//        $phone = $this->_getRequestValue('phone');
//        $verificationCode = $this->_getRequestValue('verification_code');
//
//        $user = User::loginWithPhone($institutionCode, $phone, $verificationCode);
//        return $this->renderJson($user);
//    }

    /**
     * 系统直接获取用户登录信息
     * @return string
     */
    public function actionAutoLogin()
    {
        $institutionCode = $this->_getInstitutionCode();

        $userCode = $this->_getRequestValue('user_code');
        $userName = $this->_getRequestValue('user_name');

        $user = User::autoLogin($institutionCode, $userCode, $userName);
        return $this->renderJson($user);
    }

    /**
     * 获取用户信息
     * @return string
     */
    public function actionGetUserDetail()
    {
        $userId = $this->_authUserTicket();

        $item = User::getUserDetail($userId);
        return $this->renderJson($item);
    }

//    /**
//     * 修改用户电话用户名
//     * @return string
//     */
//    public function actionSetUserName()
//    {
//        $userId = $this->_authUserTicket();
//        $name = $this->_getRequestValue('name');
//        $phone = $this->_getRequestValue('phone');
//        $rt = User::setUserName($userId, $name, $phone);
//        return $this->renderJson();
//    }

//    /**
//     * 获取机构信息
//     * @return string
//     */
//    public function actionGetInstitution()
//    {
//        $institutionCode = $this->_getInstitutionCode();
//        $institution = Institution::getInstitutionByCode($institutionCode);
//        return $this->renderJson($institution);
//    }

    /**
     * @return string
     * @throws \Exception
     * @throws \yii\db\Exception
     */
    public function actionSendUserIntegral()
    {
        $institutionCode = $this->_getRequestValue('institution_code');
        $userId = $this->_getRequestValue('user_id');
        $integral = $this->_getRequestValue('integral');

        $data = [
            'institutionCode' => $institutionCode,
            'user_id' => $userId,
            'integral' => $integral
        ];

        $result = Integral::sendUserIntegral($data);
        return $this->renderJson(null, $result);
    }

    /**
     * 通过电话号码给用户发送积分
     * @return string
     */
    public function actionSendUserIntegralByPhone()
    {
        $institutionCode = $this->_getRequestValue('institution_code');
        $phone = $this->_getRequestValue('phone');
        $integral = $this->_getRequestValue('integral');

//        if($pho)

        $user = User::getUserByPhone($institutionCode, $phone);
        if($user == null){
            //增加此用户
            $record['phone']=$phone;
            $record['institution_code'] = $institutionCode;
            $record['id'] = 0;
            $record['code'] = 0;
            $record['name'] = '';
            $record['remark'] = '';
            $record['isEnabled'] = 1;
            $record['wx_openid'] = '';
            $record['header_url'] = '';
//            $record['department_id'] = $departmentId;
            $user = User::addUser($record);
            $user['id'] = $user['userId'];
            if($user == '')
            return $this->renderJson(null, 1, "未找到此用户。");
        }

        $userId = $user['id'];

        $data = [
            'institutionCode' => $institutionCode,
            'user_id' => $userId,
            'integral' => $integral
        ];

        $result = Integral::sendUserIntegral($data);
        return $this->renderJson(null, $result);
    }

    /**
     * 获取用户当前积分
     * @return string
     */
    public function actionGetUserIntegral()
    {
        $userId = $this->_authUserTicket();
        $integral = User::getUserIntegral($userId);
        return $this->renderJson($integral);
    }

    /**
     * 用电话号码获取用户当前积分
     * @return string
     */
    public function actionGetUserIntegralByPhone()
    {
        $institutionCode = $this->_getRequestValue('institution_code');
        $phone = $this->_getRequestValue('phone');
        $user = User::getUserByPhone($institutionCode, $phone);
        if($user == null){
            return $this->renderJson(null, 1, "未找到此用户。");
        }

        $userId = $user['id'];
        $integral = User::getUserIntegral($userId);
        return $this->renderJson($integral);
    }

    /**
     * 获取用户账户积分变更记录
     * @return string
     */
    public function actionGetUserIntegralRecord()
    {
        $userId = $this->_authUserTicket();
        $page = $this->_getRequestValue('page', 1);
        $pageSize = $this->_getRequestValue('page_size', 10);

        $count = Api::getIntegralRecordCountByUser($userId);
        $items = Api::getIntegralRecordListByUser($userId, $page, $pageSize);

        $result = [
            'count' => $count,
            'page' => $page,
            'page_size' => $pageSize,
            'list' => $items
        ];

        return $this->renderJson($result);
    }

//    /**
//     * 获取用户最近半年累计进账积分
//     * @return string
//     */
//    public function actionGetIntegralTotalByUser()
//    {
//        $userId = $this->_authUserTicket();
//        $integralTotal = Integral::getIntegralTotalByUser($userId, 1);
//        return $this->renderJson($integralTotal);
//    }

    /**
     * 获取用户购物车
     * @return string
     */
    public function actionGetCart()
    {
        $userId = $this->_authUserTicket();

        $items = Cart::getCart($userId);
        return $this->renderJson($items);
    }

    /**
     * 选择商品添加到购物车
     * @return string
     * @throws \Exception
     */
    public function actionAddCart()
    {
        $userId = $this->_authUserTicket();
        $goodsCode = $this->_getRequestValue('goods_code');
        $quantity = $this->_getRequestValue('quantity', 1);

        $cartId = Cart::addCart($userId, $goodsCode, $quantity);
        return $this->renderJson($cartId);
    }

    /**
     * 修改某用户购物车中商品数
     * @return string
     * @throws \Exception
     */
    public function actionSetCartQuantity()
    {
        $userId = $this->_authUserTicket();
        $cartId = $this->_getRequestValue('cart_id');
        $quantity = $this->_getRequestValue('quantity');

        Cart::setCartQuantity($userId, $cartId, $quantity);
        return $this->renderJson(null);
    }

    /**
     * 移除某用户购物车中的某件商品
     * @return string
     * @throws \Exception
     */
    public function actionRemoveCart()
    {
        $userId = $this->_authUserTicket();
        $cartId = $this->_getRequestValue('cart_id');

        Cart::removeCart($userId, $cartId);
        return $this->renderJson(null);
    }

    /**
     * 设置某用户购物车的某件商品是否选中,选中的商品将进行结算
     * @return string
     */
    public function actionSetCartSelected()
    {
        $userId = $this->_authUserTicket();
        $cartId = $this->_getRequestValue('cart_id');
        $isSelected = $this->_getRequestValue('is_selected');

        Cart::setCartSelected($userId, $cartId, $isSelected);
        return $this->renderJson();
    }

    /**
     * 获取某用户购物车中选择的所有商品,用于准备生成订单时使用
     * @return string
     */
    public function actionGetCartSelected()
    {
        $userId = $this->_authUserTicket();

        $items = Cart::getCartSelected($userId);
        return $this->renderJson($items);
    }

    /**
     * 获取物流三级体系数据
     * @return string
     */
    public function actionGetAreaList()
    {
        $parentId = $this->_getRequestValue('parent_id', '');

        $items = Area::getAreaList($parentId);
        return $this->renderJson($items);
    }

    /**
     * 获取某用户的所有收货地址
     * @return string
     */
    public function actionGetAddressList()
    {
        $userId = $this->_authUserTicket();

        $items = Address::getUserAllAddress($userId);
        return $this->renderJson($items);
    }

    /**
     * 添加用户收货地址
     * @return string
     */
    public function actionAddAddress()
    {
        $userId = $this->_authUserTicket();
        $name = $this->_getRequestValue('name');
        $phone = $this->_getRequestValue('phone');
        $provinceName = $this->_getRequestValue('province_name');
        $cityName = $this->_getRequestValue('city_name');
        $regionName = $this->_getRequestValue('region_name');
        $address = $this->_getRequestValue('address');
        $remark = $this->_getRequestValue('remark', '');

        $addressId = Address::saveAddress($userId, null, $name, $phone, $provinceName, $cityName, $regionName, $address, $remark);
        return $this->renderJson($addressId);
    }

    /**
     * 编辑用户收货地址(如果未找到此addressId地址,则新增地址)
     * @return string
     */
    public function actionSetAddress()
    {
        $userId = $this->_authUserTicket();
        $addressId = $this->_getRequestValue('address_id', '');
        $name = $this->_getRequestValue('name');
        $phone = $this->_getRequestValue('phone');
        $provinceName = $this->_getRequestValue('province_name');
        $cityName = $this->_getRequestValue('city_name');
        $regionName = $this->_getRequestValue('region_name');
        $address = $this->_getRequestValue('address');
        $remark = $this->_getRequestValue('remark', '');

        $addressId = Address::saveAddress($userId, $addressId, $name, $phone, $provinceName, $cityName, $regionName, $address, $remark);
        return $this->renderJson($addressId);
    }

    /**
     * 删除用户收货地址
     * @return string
     */
    public function actionDeleteAddress()
    {
        $userId = $this->_authUserTicket();
        $addressId = $this->_getRequestValue('address_id');

        $result = Address::deleteAddress($userId, $addressId);
        if ($result == 0) {
            return $this->renderJson();
        } else {
            return $this->renderJson(null, ApiResponseCode::OtherErrorCode, '删除收货地址失败!');
        }
    }

    /**
     * 获取某用户的默认收货地址
     * @return string
     */
    public function actionGetDefaultAddress()
    {
        $userId = $this->_authUserTicket();

        $item = Address::getDefault($userId);
        return $this->renderJson($item);
    }

    /**
     * 设置用户的默认收货地址
     * @return string
     */
    public function actionSetDefaultAddress()
    {
        $userId = $this->_authUserTicket();
        $addressId = $this->_getRequestValue('address_id');

        $result = Address::setDefault($userId, $addressId);
        if ($result == 0) {
            return $this->renderJson();
        } else {
            return $this->renderJson(null, ApiResponseCode::OtherErrorCode, '设置默认地址错误');
        }
    }

    /**
     * 获取某个收货地址详情
     * @return string
     */
    public function actionGetAddressDetail()
    {
        $addressId = $this->_getRequestValue('address_id');
        $items = Address::getDetail($addressId);
        return $this->renderJson($items);
    }

    /**
     * 获取某个用户账户信息
     */
    public function actionGetUserAccountDetail()
    {

    }

    /**
     * 根据系统中用户的数据来生成订单
     * @return string
     */
    public function actionAddOrderWithUser()
    {
        $userId = $this->_authUserTicket();
        $remark = $this->_getRequestValue('order_remark', '');
        $idcardName = $this->_getRequestValue('idcard_name', '');
        $idcardNumber = $this->_getRequestValue('idcard_number', '');

        $hasCrossborder = false;
        $goodsList = Cart::getCartSelected($userId);
        foreach ($goodsList as $goods) {
            if ($goods['is_crossborder'] == 1) {
                $hasCrossborder = true;
                break;
            }
        }
        if ($hasCrossborder == true) {
            if (empty($idcardName) || empty($idcardNumber)) {
                throw new \Exception('购买跨境商品必须提供身份证信息!');
            }
        }

        //todo:--2016-11-19 添加跨境商品 姓名 身份
        $orderId = Order::addWithUser($userId, $remark, $idcardName, $idcardNumber);
        return $this->renderJson($orderId);
    }

    /**
     * 根据传入的数据来生成订单
     * @return string
     * @throws \Exception
     */
    public function actionAddOrderWithOpenAnonymous()
    {
        $institutionCode = $this->_getInstitutionCode();
        $receiver = (array)$this->_getRequestValue('receiver');
        $goodsList = (array)$this->_getRequestValue('goods_list');
        $remark = $this->_getRequestValue('order_remark', '');
        $tag = $this->_getRequestValue('tag', '');
        $idcardName = $this->_getRequestValue('idcard_name', '');
        $idcardNumber = $this->_getRequestValue('idcard_number', '');

        $data = [
            'institution_code' => $institutionCode,
            'receiver' => $receiver,
            'goods_list' => $goodsList,
            'remark' => $remark,
            'tag' => $tag,
            'idcardName' => $idcardName,
            'idcardNumber' => $idcardNumber
        ];

        // TODO  $data增加$data['idcardName'], $data['idcardNumber']

        $item = Order::addOrderWithOpenAnonymous($data);
        return $this->renderJson($item);
    }

    /**
     * 获取某用户订单列表
     * @return string
     */
    public function actionGetOrderList()
    {
        $userId = $this->_authUserTicket();
        $page = $this->_getRequestValue('page', 1);
        $pageSize = $this->_getRequestValue('page_size', 10);

        $count = Order::getListCountByUser($userId);
        $items = Order::getListByUser($userId, ($page - 1) * $pageSize, $pageSize);

        $result = [
            'count' => $count,
            'page' => $page,
            'page_size' => $pageSize,
            'list' => $items
        ];
        return $this->renderJson($result);
    }

    /**
     * 通过tag来获取订单列表
     * @return string
     */
    public function actionGetOrderListWithTag()
    {
        $institutionCode = $this->_getInstitutionCode();
        $page = $this->_getRequestValue('page', 1);
        $pageSize = $this->_getRequestValue('page_size', 10);
        $tag = $this->_getRequestValue('tag');

        $count = Order::getOrderCountWithTag($institutionCode, $tag);
        $items = Order::getOrderListWithTag($institutionCode, $tag, ($page - 1) * $pageSize, $pageSize);

        $result = [
            'count' => $count,
            'page' => $page,
            'page_size' => $pageSize,
            'list' => $items
        ];
        return $this->renderJson($result);
    }

    /**
     * 获取订单详情
     * @return string
     */
    public function actionGetOrderDetail()
    {
        $userId = $this->_authUserTicket();
        $orderId = $this->_getRequestValue('order_id');

        $item = Order::getDetailWithUser($userId, $orderId);
        return $this->renderJson($item);
    }

    /**
     * 根据订单编号来获取订单详情
     * @return string
     */
    public function actionGetOrderDetailByCode()
    {
        $orderCode = $this->_getRequestValue('order_code');

        $item = Order::getDetailByCode($orderCode);
        return $this->renderJson($item);
    }

    /**
     * 获取订单配送信息
     * @return string
     */
    public function actionGetOrderDelivery()
    {
        $orderCode = $this->_getRequestValue('order_code');

        $items = Order::getOrderDelivery($orderCode);
        return $this->renderJson($items);
    }

    /**
     * 获取物流信息
     * @return string
     * @throws \Exception
     */
    public function actionGetLogisticsRecord()
    {
        $logisticsCode = $this->_getRequestValue('logistics_code');
        try {
            $items = Inteface::getExpressTrackRecord($logisticsCode);
            return $this->renderJson($items);
        } catch (\Exception $ex) {
            throw new \Exception('查询失败!');
        }
    }

    /**
     * 取消订单
     * @return string
     */
    public function actionCancelOrder()
    {
        $orderCode = $this->_getRequestValue('order_code');
        $remark = $this->_getRequestValue('remark', '');
        $status = Order::cancelOrder($orderCode, $remark);
        switch ($status) {
            case 0:
                return $this->renderJson();
                break;
            case 20:
                return $this->renderJson(null, ApiResponseCode::OtherErrorCode, '取消订单失败!');
                break;
            case 21:
                return $this->renderJson(null, ApiResponseCode::OtherErrorCode, '此订单不能取消!');
                break;
            default:
                return $this->renderJson(null, ApiResponseCode::OtherErrorCode, '取消订单失败!');
                break;
        }
    }

    /**
     * 确认收货
     */
    public function actionSetOrderCompleted()
    {

    }

    /**
     * 根据identifier code获取广告列表
     * @return string
     */
    public function actionGetAdList()
    {
        $institutionCode = $this->_getInstitutionCode();
        $identifierCode = $this->_getRequestValue('identifier_code');

        $item = MallFrontEnd::getAdByIdentifier($institutionCode, $identifierCode);
        return $this->renderJson($item);
    }

    public function beforeAction($action)
    {
        $isRecordLog = \Yii::$app->params['isRecordLog'];
        if ($isRecordLog == true) {
            // 记录请求日志
            $logId = ApiOperateLog::add(
                $action->id,
                $_GET,
                $_POST,
                \Yii::$app->request->get('account'),
                \Yii::$app->request->get('timestamp'),
                \Yii::$app->request->get('sign'),
                $_SERVER['REMOTE_ADDR'],
                $_SERVER['REQUEST_TIME']
            );
            \Yii::$app->session->set('request_api_operate_log_id', $logId);
            \Yii::$app->session->set('request_api_timestamp', Tools::getMillisecond());
        }

        if (YII_ENV != 'dev') {
            if (!$this->_auth()) {
                return false;
            }
        }

        $this->_request = json_decode(file_get_contents("php://input"));
        return parent::beforeAction($action);
    }

    /**
     * 重写基类runAction,已处理所有action异常
     * @param string $id
     * @param array $params
     * @return mixed|void
     */
    public function runAction($id, $params = [])
    {
        try {
            return parent::runAction($id, $params);
        } catch (\Exception $ex) {
            $isRecordLog = \Yii::$app->params['isRecordLog'];
            if ($isRecordLog == true) {
                // 记录异常日志
                $logId = \Yii::$app->session->get('request_api_operate_log_id');
                if ($logId != null) {
                    ApiOperateLog::setException($logId, $ex);

                    $operateLog = ApiOperateLog::getById($logId);
                    if ($operateLog != null) {
                        ApiExceptionLog::add(
                            $operateLog->actionId,
                            $operateLog->getParams,
                            $operateLog->postParams,
                            $operateLog->account,
                            $operateLog->timestamp,
                            $operateLog->sign,
                            $operateLog->remoteAddr,
                            $operateLog->createDatetime,
                            $ex
                        );
                    }
                }
            }

            return $this->_errorHandler($ex);
        }
    }

    public function afterAction($action, $result)
    {
        $isRecordLog = \Yii::$app->params['isRecordLog'];
        if ($isRecordLog == true) {
            // 记录请求总共耗时(毫秒)
            $logId = \Yii::$app->session->get('request_api_operate_log_id');
            if ($logId != null) {
                $time = Tools::getMillisecond();
                $time = $time - \Yii::$app->session->get('request_api_timestamp');
                ApiOperateLog::setDurationTime($logId, $time);
            }
        }

        return parent::afterAction($action, $result);
    }

    /**
     * 自定义的错误处理返回json
     * @param \Exception $ex
     * @return string
     */
    private function _errorHandler($ex)
    {
        try {
            throw $ex;
        } catch (ApiAccountMissingException $e) {
            if (YII_DEBUG == true) {
                return $this->renderJson(null, ApiResponseCode::AccountMissingCode, ApiResponseCode::AccountMissingMessage);
            } else {
                return $this->renderJson(null, ApiResponseCode::ExceptionCode, ApiResponseCode::ExceptionMessage . ':' . $ex->getMessage());
            }
        } catch (\Exception $e) {
            if (YII_DEBUG == true) {
                return $this->renderJson(null, ApiResponseCode::ExceptionCode, ApiResponseCode::ExceptionMessage . ':' . $ex->getMessage());
            } else {
                return $this->renderJson(null, ApiResponseCode::ExceptionCode, ApiResponseCode::ExceptionMessage . ':' . $ex->getMessage());
            }
        }
    }

    /**
     * 接口返回通用数据结构
     * @param array|mixed $data
     * @param int $status [0:success]
     * @param string $message
     * @return string
     */
    public function renderJson($data = null, $status = 0, $message = 'success')
    {
        $result = [
            'status' => $status,
            'message' => $message,
            'data' => $data
        ];

        return json_encode($result, true);
    }

    /**
     * 接口签名验证
     * @return bool
     */
    private function _auth()
    {
        // 缺少account参数
        $account = \Yii::$app->request->get('account');
        if ($account == null) {
            $this->_logException(new \Exception(ApiResponseCode::AccountMissingMessage, ApiResponseCode::AccountMissingCode));
            echo $this->renderJson(null, ApiResponseCode::AccountMissingCode, ApiResponseCode::AccountMissingMessage);  // 缺少账户信息 (1001)
            return false;
        }

        // 缺少timestamp参数
        $timestamp = \Yii::$app->request->get('timestamp');
        if ($timestamp == null) {
            $this->_logException(new \Exception(ApiResponseCode::TimestampMissingMessage, ApiResponseCode::TimestampMissingCode));
            echo $this->renderJson(null, ApiResponseCode::TimestampMissingCode, ApiResponseCode::TimestampMissingMessage);  // 缺少时间戳
            return false;
        }

        // 缺少verify参数
        $verify = \Yii::$app->request->get('verify');
        if ($verify == null) {
            $this->_logException(new \Exception(ApiResponseCode::VerifyMissingMessage, ApiResponseCode::VerifyMissingCode));
            echo $this->renderJson(null, ApiResponseCode::VerifyMissingCode, ApiResponseCode::VerifyMissingMessage);
            return false;
        }

        // 缺少sign参数
        $sign = \Yii::$app->request->get('sign');
        if ($sign == null) {
            $this->_logException(new \Exception(ApiResponseCode::SignMissingMessage, ApiResponseCode::SignMissingCode));
            echo $this->renderJson(null, ApiResponseCode::SignMissingCode, ApiResponseCode::SignMissingMessage);  // 缺少签名信息
            return false;
        }

        // timestamp过期
        if (abs(time() - $timestamp) > \Yii::$app->params['api.TimestampValidity']) {
            $this->_logException(new \Exception(ApiResponseCode::TimestampInvalidMessage, ApiResponseCode::TimestampInvalidCode));
            echo $this->renderJson(null, ApiResponseCode::TimestampInvalidCode, ApiResponseCode::TimestampInvalidMessage);  // 签名过期
            return false;
        }

        // sign认证
        $token = $this->_getAccountToken();
        $authSign = hash_hmac('sha256', $account . $token . $timestamp . $verify, $token);
        if ($authSign != $sign) {
            $this->_logException(new \Exception(ApiResponseCode::SignAuthFailedMessage, ApiResponseCode::SignAuthFailedCode));
            echo $this->renderJson(null, ApiResponseCode::SignAuthFailedCode, ApiResponseCode::SignAuthFailedMessage);  // 签名认证失败
            return false;
        }

        // 请求校验
        if ($this->_checkVerify($account, $verify) == false) {
            $this->_logException(new \Exception(ApiResponseCode::VerifyInvalidMessage, ApiResponseCode::VerifyInvalidCode));
            echo $this->renderJson(null, ApiResponseCode::VerifyInvalidCode, ApiResponseCode::VerifyInvalidMessage);
            return false;
        }

        return true;
    }

    /**
     * 校验verify。如果已经存在此verify,则此请求校验信息无效。如果不存在verify,则记录此verify。
     * @param $account
     * @param $verify
     * @return bool
     */
    private function _checkVerify($account, $verify)
    {
        $key = 'api_verify:' . $account . $verify;
        if (\Yii::$app->cache->exists($key)) {
            return false;
        } else {
            \Yii::$app->cache->set($key, null, 65);
            return true;
        }
    }

    /**
     * 根据account获取对应的open config
     * @return mixed|null
     * @throws ApiAccountMissingException
     */
    private function _getOpenConfig()
    {
        // 缺少account参数
        $account = \Yii::$app->request->get('account');
        if ($account == null) {
            throw new ApiAccountMissingException();
//            echo $this->renderJson(null, ApiResponseCode::AccountMissingCode, ApiResponseCode::AccountMissingMessage);  // 缺少账户信息 (1001)
//            return null;
        }

        $cacheKey = self::CacheKeyPrefix . '_getOpenConfig:' . $account;
        if ($this->_openConfig == null) {
            $this->_openConfig = \Yii::$app->cache->get($cacheKey);
            if ($this->_openConfig == false) {
                $this->_openConfig = null;
            }
        }

        if ($this->_openConfig != null) {
            if ($this->_openConfig['account'] != $account) {
                $this->_openConfig = null;
            }
        }
        if ($this->_openConfig == null) {
            $this->_openConfig = Open::getConfigByAccount($account);
            \Yii::$app->cache->set($cacheKey, $this->_openConfig, self::CacheDuration);
        }
        return $this->_openConfig;
    }

    /**
     * 获取account的token
     * @return string
     */
    private function _getAccountToken()
    {
        $openConfig = $this->_getOpenConfig();
        if ($openConfig == null) {
            return '';
        }

        $token = $openConfig['token'];
        return $token;
    }

    /**
     * 根据account获取对应的机构编码
     * @return bool|string
     * @throws \Exception
     */
    private function _getInstitutionCode()
    {
        $openConfig = $this->_getOpenConfig();
        if ($openConfig == null) {
            return '';
        }

        if ($openConfig['is_agent'] == 0) {  // 如果此配置非代理商,那么机构编码取account所对于的机构。
            $institutionCode = $openConfig['institution_code'];
        } else {  // 如果此配置为代理商配置,那么机构编码取post传入进来的institution_code参数,并验证此institution_code为此代理商或此代理商的旗下机构。
            $configInstitutionCode = $openConfig['institution_code'];
            $institutionCode = $this->_getRequestValue('institution_code');
            if ($institutionCode != $configInstitutionCode) {
                $cacheKey = self::CacheKeyPrefix . 'Institution::getInstitutionByCode:' . $institutionCode;
                $t = \Yii::$app->cache->get($cacheKey);
                if ($t == false) {
                    $t = Institution::getInstitutionByCode($institutionCode);
                    \Yii::$app->cache->set($cacheKey, $t, self::CacheDuration);
                }
                if ($t['parent_code'] != $configInstitutionCode) {
                    $institutionCode = '';
                }
            }
        }
        return $institutionCode;
    }

    /**
     * 获取post传入进来的某个参数值
     * @param $request
     * @param string $paramName 参数名
     * @param null|string|int|float $defaultValue
     * @return mixed|null
     */
    private function _getRequestParamValue($request, $paramName, $defaultValue = null)
    {
        $returnValue = null;
        $request = (array)$request;
        if (isset($request[$paramName])) {
            $returnValue = $request[$paramName];
        }
        if ($returnValue == null) {
            if (isset($defaultValue)) {
                $returnValue = $defaultValue;
            } else {
                echo $this->renderJson(null, ApiResponseCode::ParamMissingCode, ApiResponseCode::ParamMissingMessage . ': ' . $paramName);
                exit;
            }
        }
        return $returnValue;
    }

    /**
     * 获取当前这次post传入进来的某个参数值
     * @param string $paramName 参数名
     * @param null|string|int|float $defaultValue
     * @return mixed|null
     */
    private function _getRequestValue($paramName, $defaultValue = null)
    {
        return $this->_getRequestParamValue($this->_request, $paramName, $defaultValue);
    }

    /**
     * 验证用户ticket
     * @return int userId
     * @throws \Exception
     */
    private function _authUserTicket()
    {
        $userTicket = $this->_getRequestValue('user_ticket');
        $userId = User::authUserTicket($userTicket);
//        $userId = '2';
        if ($userId == null) {
            $this->_logException(new \Exception(ApiResponseCode::UserTicketErrorMessage, ApiResponseCode::UserTicketErrorCode));
            echo $this->renderJson(null, ApiResponseCode::UserTicketErrorCode, ApiResponseCode::UserTicketErrorMessage);
            exit;
        }
        return $userId;
    }

    /**
     * 记录当前会话的异常日志
     * @param $ex
     */
    private function _logException($ex)
    {
        $isRecordLog = \Yii::$app->params['isRecordLog'];
        if ($isRecordLog == true) {
            // 记录异常日志
            $logId = \Yii::$app->session->get('request_api_operate_log_id');
            if ($logId != null) {
                ApiOperateLog::setException($logId, $ex);

                $operateLog = ApiOperateLog::getById($logId);
                if ($operateLog != null) {
                    ApiExceptionLog::add(
                        $operateLog->actionId,
                        $operateLog->getParams,
                        $operateLog->postParams,
                        $operateLog->account,
                        $operateLog->timestamp,
                        $operateLog->sign,
                        $operateLog->remoteAddr,
                        $operateLog->createDatetime,
                        $ex
                    );
                }
            }
        }
    }
}